use alloc::{vec, vec::Vec};

use crate::memory::{
    mapping::{
        mapping::*,
        segment::{
            Segment,
            MapType
        },
        page_table_entry::Flags,
    },
    address::VirtualAddress,
    config::KERNEL_END_ADDRESS,
    MemoryResult,
    range::Range,
};

pub struct MemorySet {
    pub mapping: Mapping,
    pub segments: Vec<Segment>,
}

impl MemorySet {
    pub fn new_kernel() -> MemoryResult<MemorySet> {
        extern "C" {
            fn text_start();
            fn rodata_start();
            fn data_start();
            fn bss_start();
        }

        let segments = vec![
            Segment {
                map_type: MapType::Linear,
                range: Range::from((text_start as usize)..(rodata_start as usize)),
                flags: Flags::READABLE | Flags::EXECUTABLE,
            },
            Segment {
                map_type: MapType::Linear,
                range: Range::from((rodata_start as usize)..(data_start as usize)),
                flags: Flags::READABLE,
            },
            Segment {
                map_type: MapType::Linear,
                range: Range::from((data_start as usize)..(bss_start as usize)),
                flags: Flags::READABLE | Flags::WRITABLE,
            },
            Segment {
                map_type: MapType::Linear,
                range: Range::from(VirtualAddress::from(bss_start as usize)..*KERNEL_END_ADDRESS),
                flags: Flags::READABLE | Flags::WRITABLE,
            }
        ];
        let mut mapping = Mapping::new()?;
        for segment in segments.iter() {
            mapping.map(segment, None)?;
        }
        
        Ok(MemorySet { mapping, segments })
    }
    
    pub fn active(&self) {
        self.mapping.activate()
    }
}
